from flask import request, current_app, make_response, jsonify, session, redirect, url_for
from info.models import User
from info.response_code import RET
from info.modules.passport import passport_bp
from info.utils.captcha.captcha import captcha
from info import redis_store, constants, db
import re
from info.lib.yuntongxun.sms import CCP
import random
from datetime import datetime


# "/passport/image_code?code_id=" + imageCodeId;
@passport_bp.route("/image_code")
def get_image_code():
    """获取图片验证码的后端端口"""
    # 1.获取参数
    # 1.1获取图片验证码编号code_id
    code_id = request.args.get("code_id")
    # 2.校验参数
    # 2.1判断编码是否存在
    if not code_id:
        current_app.logger.error("图片验证码编号不存在")
        return jsonify(errno=RET.PARAMERR, errmsg='图片验证码编号不存在')
    # 3.业务逻辑
    # 3.1编码存在,生成图片验证码和验证码图片真实值
    image_name, real_image_code, image_data = captcha.generate_captcha()
    # 3.2将生成的真实验证码真实值进行保存,设置时长,code_id作为键
    try:
        redis_store.setex("ImageCode_" + code_id, constants.IMAGE_CODE_REDIS_EXPIRES, real_image_code)
    except Exception as result:
        current_app.logger.error(result)
        return jsonify(errno=RET.DATAERR, errmsg='保存图片验证码失败')
    # 4.返回数据(值)
    # 4.1将生成的验证码返回,设置返回的数据类型
    resp = make_response(image_data)
    resp.headers["Content-Type"] = "image/jpg"
    return resp


# "/passport/sms_code"
@passport_bp.route("/sms_code", methods=["POST"])
def send_sms_code():
    # 1.接受参数
    # 1.1 参数有 mobile手机号, 用户输入的图片验证码值image_code, 数据数据库中保存的图片验证验证码真实值的编号 image_code_id
    # request.json自动将json数据转换为字典格式
    param_dict = request.json
    mobile = param_dict.get("mobile")
    image_code = param_dict.get("image_code")
    image_code_id = param_dict.get("image_code_id")

    # 2.校验参数
    # 2.1 判段参数是否为空
    if not all([mobile, image_code, image_code_id]):
        current_app.logger.error("参数不全")
        return jsonify(errno=RET.PARAMERR, errmsg='参数不全')
    # 3.业务逻辑
    # 3.1 判断手机号格式是否正确
    if not re.match("^1[3456789][0-9]{9}$", mobile):
        current_app.logger.error("手机格式不正确")
        return jsonify(errno=RET.PARAMERR, errmsg='手机格式不正确')

    # 3.2 从数据库中取出验证码真实值
    try:
        real_image_code = redis_store.get("ImageCode_" + image_code_id)
    except Exception as result:
        # 3.1.1如果不存在,数据过期
        current_app.logger.error(result)
        return jsonify(errno=RET.DBERR, erromsg='获取验证码失败')

    # 3.2.1判断验证码是否存在
    if not real_image_code:
        # 如果不存在,提示用户验证码过期,
        current_app.logger.error("验证码过期")
        return jsonify(errno=RET.NODATA, erromsg='验证码过期')
    else:
        try:
            # 如果不存,则删除数据过的验证码,防止一个验证码进行多次验证
            redis_store.delete("code_id" + image_code_id)
        except Exception as result:
            current_app.logger.error(result)
    # 3.3 将数据保存的图片验证验证码真实值与用户输入的图片验证码进行比较(忽略大小写,redis数据库获取的为二进制数据,需要设置decode_responses=True)
    # 3.3.1.如果不相等,用户输入错误
    if real_image_code.lower() != image_code.lower():
        current_app.logger.error("输入的验证码错误")
        return jsonify(errno=RET.DATAERR, erromsg='输入的验证码错误')
    # 3.3.2如果相等,发送短信,但在发送短信之前需要判断用户是否已经注册
    try:
        user = User.query.filter(User.mobile == mobile).first()
    except Exception as result:
        current_app.logger.error(result)
        return jsonify(errno=RET.DBERR, erromsg='获取用户信息失败')
    # 如果用户存在,表示用户已经注册
    # if user:
    #     return jsonify(errno=RET.DATAEXIST, errmsg='该手机号已经注册')
    # 3.3.3 编辑短信内容并发送短信
    print(123)
    sms_content = random.randint(0, 999999)
    # 不足6位用零补充
    sms_content = "%06d" % sms_content
    # 发送短信
    result = CCP().send_template_sms(mobile, {sms_content, constants.SMS_CODE_REDIS_EXPIRES / 60}, 1)
    # 3.3.4 判断短信是否发送成功
    if result != 0:
        return jsonify(errno=RET.THIRDERR, erromsg='短信发送失败')
    # 如果短信发送将短信验证码保存到redis数据库
    try:
        redis_store.setex("SMS_" + mobile, constants.SMS_CODE_REDIS_EXPIRES, sms_content)
    except Exception as result:
        current_app.logger.error(result)
        return jsonify(errno=RET.DATAERR, errmsg='保存验证码失败')
    # 4.1 返回值,短信发送成功,提示用户等待
    return jsonify(errno=RET.OK, errmsg='短信发送成功')


@passport_bp.route("/register", methods=["POST"])
def register():
    # 1.获取参数,参数有 mobile手机号,用户收到的短信验证码sms_code,密码password
    param_dict = request.json
    mobile = param_dict.get("mobile")
    sms_code = param_dict.get("sms_code")
    password = param_dict.get("password")
    # 2.校验参数
    print(mobile)
    print(sms_code)
    print(password)
    # 2.1 非空判断
    if not all([mobile, sms_code, password]):
        current_app.logger.error("参数不全")
        return jsonify(errno=RET.PARAMERR, errmsg='参数不全')
    # 2.2 手机格式判断
    if not re.match("^1[3456789][0-9]{9}$", mobile):
        current_app.logger.error("手机格式不正确")
        return jsonify(errno=RET.PARAMERR, errmsg='手机格式不正确')

    # 3.业务逻辑
    # 3.1 将用户输入的验证码与数据库保存的验证码进行比较
    # 3.1.1 取出数据库保存的验证码,如果有值,则删除;如果没有,则提示过期
    try:
        real_sms_code = redis_store.get("SMS_" + mobile)
    except Exception as result:
        current_app.logger.error(result)
        return jsonify(errno=RET.DBERR, errmsg="获取验证码失败")
    # 如果没有,则提示过期
    if not real_sms_code:
        return jsonify(errno=RET.NODATA, errmsg="验证码过期")
    # 如果有值, 则删除;
    else:
        try:
            redis_store.delete("SMS_" + mobile)
        except Exception as result:
            current_app.logger.error(result)
            return jsonify(errno=RET.DBERR, errmsg="删除验证码失败")

    # 3.1.2 将数据库中取出的验证码和用户输入的进行比较
    if real_sms_code != sms_code:
        current_app.logger.error("输入的短信验证码错误")
        return jsonify(errno=RET.PARAMERR, errmsg="输入的短信验证码错误")

    # 3.2 判断密码的位数至少6位
    if not (len(password) >= 6 and len(password) <= 20):
        current_app.logger.error("设置的密码不符合要求")
        return jsonify(errno=RET.PARAMERR, errmsg="设置的密码不符合要求")
    # 3.3 将用户信息进行注册保存
    # 用户信息
    user = User()
    user.mobile = mobile
    user.nick_name = mobile
    user.password = password
    user.last_login = datetime.now()
    try:
        db.session.add(user)
        db.session.commit()
    except Exception as result:
        current_app.logger.error(result)
        # 数据回滚
        db.session.rollback()
        return jsonify(errno=RET.PARAMERR, errmsg="用户信息保存失败")
    # 3.3 通过session 保存用户的状态
    # 用户id
    session["id"] = user.id
    # 用户的手机号
    session["mobile"] = user.mobile
    # 用户的昵称
    session["nick_name"] = user.nick_name

    # 4.返回数据
    return jsonify(errno=RET.OK, errmsg="注册成功")


@passport_bp.route('/login', methods=["POST"])
def login():
    """后端实现登录的接口"""
    # 1.获取手机号码和密码
    param_dict = request.json
    mobile = param_dict.get("mobile")
    password = param_dict.get("password")

    # 2.校验数据是非为空和手机格式是否正确
    if not all([mobile, password]):
        current_app.logger("参数不全")
        return jsonify(errno=RET.PARAMERR, errmsg="参数不全")
    if not re.match("^1[3456789][0-9]{9}$", mobile):
        current_app.logger.error("手机格式不正确")
        return jsonify(errno=RET.PARAMERR, errmsg='手机格式不正确')
    # 3.登录业务逻辑
    # 3.1 查询数据库,判断用户是否存在
    user = None
    try:
        user = User.query.filter(User.mobile == mobile).first()
    except Exception as result:
        current_app.logger(result)
        jsonify(errno=RET.DBERR, errmsg="查询数据异常")
    # 3.1.1如果不存在,返回登录错误信息
    if not user:
        jsonify(errno=RET.NODATA, errmsg="用户不存在")
    # 3.2 用户存在,检查密码是否正确
    if not user.check_passowrd(password):
        # 3.2.1 密码不正确,返回密码错误
        return jsonify(errno=RET.PWDERR, errmsg="密码不存在")
    # 3.3 修改用户最后一次登录的时间last_login,保存到数据库
    try:
        user.last_login = datetime.now()
        db.session.commit()
    except Exception as result:
        current_app.logger.error(result)
        jsonify(errno=RET.DBERR, errmsg="修改数据异常")
    # 3.4 对用户的登录状态通过设置session进行保持
    # 3.3 通过session 保存用户的状态
    # 用户id
    session["id"] = user.id
    # 用户的手机号
    session["mobile"] = user.mobile
    # 用户的昵称
    session["nick_name"] = user.nick_name
    # 4.返回用户登录成功
    return jsonify(errno=RET.OK, errmsg="登录成功")


# post请求url地址: /passport/login_out
@passport_bp.route('/login_out', methods=["POST", "GET"])
def login_out():
    """后端实现登出接口"""
    # 1.删除session数据
    session.pop("id", None)
    session.pop("mobile", None)
    session.pop("nick_name", None)
    is_admin = session.get("is_admin")
    if is_admin:
        session.pop("is_admin", None)
        return redirect(url_for("admin_info.login"))
    # 2.返回结果
    return jsonify(errno=RET.OK, errmsg="删除成功")
